// --------------------------------------------------------------------------------------------------------------------- 
// <copyright file="ServerConnectionService.cs" company="Scrum for Team System">
//   None
// </copyright>
// <summary>
//   Defines the ServerConnectionService type.
// </summary>
// ---------------------------------------------------------------------------------------------------------------------

namespace ScrumForTeamSystem.EventService.Services
{
    using System;
    using System.Globalization;
    using System.Net;

    using Microsoft.TeamFoundation.Client;

    using ScrumForTeamSystem.EventService.Infrastructure;
    using ScrumForTeamSystem.EventService.Infrastructure.Enums;
    using ScrumForTeamSystem.EventService.Infrastructure.Interfaces;
    using ScrumForTeamSystem.EventService.Services.Properties;

    /// <summary>
    /// Defines the ServerConnectionService type.
    /// </summary>
    internal class ServerConnectionService : IServerConnectionService
    {
        /// <summary>
        /// Occurs when [action] event raised.
        /// </summary>
        public event EventHandler<ActionEventArgs> Message;

        /// <summary>
        /// Occurs when [connected state set] event raised.
        /// </summary>
        public event EventHandler<ConnectionStateChangedEventArgs> ConnectedStateSet;

        /// <summary>
        /// Occurs when [exception action] event raised.
        /// </summary>
        public event EventHandler<ExceptionActionEventArgs> ExceptionMessage;

        /// <summary>
        /// Gets a value indicating whether this instance is subscribed.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is subscribed; otherwise, <c>false</c>.
        /// </value>
        private bool IsSubscribed
        {
            get
            {
                return this.Message != null;
            }
        }

        /// <summary>
        /// Sets the state of the connection.
        /// </summary>
        /// <param name="connectionState">State of the connection.</param>
        public void SetConnectionState(ConnectionState connectionState)
        {
            if (this.ConnectedStateSet != null)
            {
                this.ConnectedStateSet(this, new ConnectionStateChangedEventArgs(connectionState));
            }
        }

        /// <summary>
        /// Gets the server URL.
        /// </summary>
        /// <param name="useSecureSocketLayer">The use ssl.</param>
        /// <param name="server">The server.</param>
        /// <param name="port">The port number.</param>
        /// <returns>The server uri as a string</returns>
        public string GetServerAddress(bool useSecureSocketLayer, string server, int port)
        {
            return string.Concat(useSecureSocketLayer ? "https" : "http", "://", server, ":", port);
        }

        /// <summary>
        /// Gets the TFS service provider.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <returns>The team foundation server instance</returns>
        public IServiceProvider GetTfsServiceProvider(string connectionString)
        {
            if (!IsNotEmptyString(connectionString))
            {
                return null;
            }

            var connectionUri = new Uri(connectionString, UriKind.Absolute);

            IServiceProvider output = null;

            var currentServer = GetCurrentServer(connectionUri);

            var isSubscribed = this.IsSubscribed;

            try
            {
                currentServer.EnsureAuthenticated();

                if (isSubscribed)
                {
                    this.Message(
                            this, new ActionEventArgs(String.Format(CultureInfo.CurrentUICulture, "Connection to TFS '{0}' made", connectionString)));
                }

                output = currentServer;
            }
            catch (Exception ex)
            {
                if (!isSubscribed)
                {
                    throw;
                }

                this.ExceptionMessage(this, new ExceptionActionEventArgs(ex));
            }
            
            return output;
        }

        /// <summary>
        /// Determines whether [the specified host] [is valid connection details].
        /// </summary>
        /// <param name="host">The host name.</param>
        /// <param name="port">The port number.</param>
        /// <returns>
        /// <c>true</c> if [the specified host] [is valid connection details]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsValidConnectionDetails(string host, int port)
        {
            var isValid = true;

            if (port <= 0 || port > 999999)
            {
                isValid = false;
            }

            if (String.IsNullOrEmpty(host))
            {
                isValid = false;
            }

            return isValid;
        }

        /// <summary>
        /// Determines whether [the specified string value] [is not empty string].
        /// </summary>
        /// <param name="stringValue">The string value.</param>
        /// <returns>
        /// <c>true</c> if [the specified string value] [is not empty string]; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsNotEmptyString(string stringValue)
        {
            return !String.IsNullOrEmpty(stringValue);
        }

        /// <summary>
        /// Gets the current server.
        /// </summary>
        /// <param name="connectionUri">The connection URI.</param>
        /// <returns>A Tfs conneciton instance.</returns>
        private static TfsConnection GetCurrentServer(Uri connectionUri)
        {
            TfsConnection currentServer;
            if (!String.IsNullOrEmpty(Settings.Default.TFS_UserDomain))
            {
                var nc = new NetworkCredential(
                    Settings.Default.TFS_UserName,
                    Settings.Default.TFS_UserPassword,
                    Settings.Default.TFS_UserDomain);

                currentServer = new TfsTeamProjectCollection(connectionUri, nc);
            }
            else
            {
                currentServer = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(connectionUri);
            }

            return currentServer;
        }
    }
}